﻿using EWSEditor.Common;
using EWSEditor.Forms;
using Microsoft.Exchange.WebServices.Data;
using Microsoft.Xrm.Sdk.Client;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml;

namespace EWSEditor.CRM.Forms
{
    public partial class RequestBuilderForm : Form
    {

        private ExchangeService _exchangeproxy;
        public string HeaderXml
        {
            get
            {
                if (_headerXml == null)
                {
                    return SetHeaderXml();
                }
                else
                {
                    return _headerXml;
                }
            }
            private set { _headerXml = value; }
        }
        private string _headerXml;

        public RequestBuilderForm(ExchangeService service)
        {
            _exchangeproxy = service;
            InitializeComponent();
            SetParameterInformation();
            SetVisibileTabs();
        }

        private void SetVisibileTabs()
        {
            if (CrmOrgMailboxCache.TargetMailboxIsQueue)
            {
                //These tabs (FindItem-ACT and SyncFolderHierarchy) are invalid for queue scenarios.
                //To-Do: When more pages are added, we will need to use Linq to query the collection by name,
                //returning the index to pass to RemoveAt().
                tabMenu.TabPages.RemoveAt(1);
                tabMenu.TabPages.RemoveAt(1);
            }
        }

        private void SetParameterInformation()
        {
            txtParamInfoFindItemEmail.Text = Strings.PARAM_INFO_FINDITEMSEMAILS;
            txtParamInfoSyncFolderHierarchy.Text = Strings.PARAM_INFO_SYNCFOLDERHIERARCHY;
            txtParamInfoACT.Text = Strings.PARAM_INFO_FINDITEMSACT;
        }

        private string SetHeaderXml()
        {
            StringBuilder sbheader = new StringBuilder();
            sbheader.Append(@"<soap:Header><RequestServerVersion Version='Exchange2010' xmlns='http://schemas.microsoft.com/exchange/services/2006/types' />");

            if (_exchangeproxy.ImpersonatedUserId != null)
            {
                sbheader.Append(@"<ExchangeImpersonation xmlns='http://schemas.microsoft.com/exchange/services/2006/types'><ConnectingSID><PrimarySmtpAddress>");
                sbheader.Append(_exchangeproxy.ImpersonatedUserId.Id);
                sbheader.Append(@"</PrimarySmtpAddress></ConnectingSID></ExchangeImpersonation>");
            }

            sbheader.Append("</soap:Header>");
            _headerXml = sbheader.ToString();
            return sbheader.ToString();
        }

        private void tabMenu_DrawItem(object sender, DrawItemEventArgs e)
        {
            
        }

        private void btnSendtoPost_Click(object sender, EventArgs e)
        {
            string currentpage = tabMenu.SelectedTab.Name;

            switch (currentpage)
            {
                case "pgFindItemEmail":
                    BuildFindItemEmail();
                    break;

                case "pgFindItemAct":
                    BuildFindItemAct();
                    break;

                case "pgSyncFolderHierarchy":
                    BuildSyncFolderHierarchy();
                    break;
            }
            
        }

        private void BuildSyncFolderHierarchy()
        {
            if (listvwSyncFolderHierarchyFolders.SelectedItems.Count == 0)
            {
                MessageBox.Show("Please select a DistinguishedFolderId");
                return;
            }

            string EnvelopeXml = @"<?xml version='1.0' encoding='utf-8'?>
  <soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:m='http://schemas.microsoft.com/exchange/services/2006/messages' xmlns:t='http://schemas.microsoft.com/exchange/services/2006/types' xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'> ";

            string BodyXml = GetSyncFolderHierarchyBody();
            SendToPostForm(BodyXml, EnvelopeXml);
        }

        private void SendToPostForm(string BodyXml, string EnvelopeXml)
        {
            string FullXml = new StringBuilder(EnvelopeXml).Append(HeaderXml).Append(BodyXml).ToString();
            PostForm postform = new PostForm(FullXml, _exchangeproxy);
            postform.Show();
        }

        private string GetSyncFolderHierarchyBody()
        {
            string foldername = GetSyncHierarchyFolderName();

            StringBuilder sbBody = new StringBuilder(@"<soap:Body>
    <m:SyncFolderHierarchy>
       <m:FolderShape>
          <t:BaseShape>AllProperties</t:BaseShape>
               <t:AdditionalProperties>
                  <t:ExtendedFieldURI PropertyTag='12292' PropertyType='String'/>
                   </t:AdditionalProperties>
                  </m:FolderShape>
                   <m:SyncFolderId>
                    <t:DistinguishedFolderId Id=");

            sbBody.Append("'").Append(foldername).Append("' />");
            sbBody.Append("</m:SyncFolderId>");
            sbBody.Append("<m:SyncState>");

            if (chkUseSyncState.Checked)
            {
                sbBody.Append(((ExchangeFolderSyncState)listvwSyncFolderHierarchyFolders.SelectedItems[0].Tag).SyncState);
            }

            sbBody.Append(@"</m:SyncState>
    </m:SyncFolderHierarchy>
  </soap:Body>
</soap:Envelope> ");

            return sbBody.ToString();
          
        }

        private string GetSyncHierarchyFolderName()
        {
            string selectedfolder = listvwSyncFolderHierarchyFolders.SelectedItems[0].Text;

            if (selectedfolder == "Contact")
            {
                return "contacts";
            }
            else if (selectedfolder == "Appointment")
            {
                return "calendar";
            }
            else
            {
                return "tasks";
            }
        }

        private void BuildFindItemAct()
        {
            string EnvelopeXml = @"<?xml version='1.0' encoding='utf-8'?><soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:m='http://schemas.microsoft.com/exchange/services/2006/messages' xmlns:t='http://schemas.microsoft.com/exchange/services/2006/types' xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>";
            string BodyXml = GetFindItemBodyForACT();
            SendToPostForm(BodyXml, EnvelopeXml);
        }

        private string GetFindItemBodyForACT()
        {
            string selectedFolder = ((ExchangeFolderSyncState)listvwFolders.SelectedItems[0].Tag).FolderId;

            StringBuilder sbBody = new StringBuilder();
            sbBody.Append(@"<soap:Body>
    <m:FindItem Traversal='Shallow'>
      <m:ItemShape>
        <t:BaseShape>IdOnly</t:BaseShape>
        <t:AdditionalProperties>
          <t:ExtendedFieldURI DistinguishedPropertySetId='PublicStrings' PropertyName='crmid' PropertyType='String'/>
          <t:ExtendedFieldURI DistinguishedPropertySetId='PublicStrings' PropertyName='crmLinkState' PropertyType='Double'/>
          <t:ExtendedFieldURI DistinguishedPropertySetId='PublicStrings' PropertyName='crmObjectTypeCode' PropertyType='Double'/>
          <t:FieldURI FieldURI='item:LastModifiedTime'/>
        </t:AdditionalProperties>
      </m:ItemShape>
      <m:IndexedPageItemView MaxEntriesReturned=").Append("'").Append(numMaxACTEntries.Value).Append("'").Append(" Offset='").Append(numACTOffset.Value).Append("' BasePoint='Beginning'/>");

            sbBody.Append(@"<m:Restriction>
        <t:Or>
          <t:IsEqualTo>
            <t:ExtendedFieldURI DistinguishedPropertySetId='PublicStrings' PropertyName='crmLinkState' PropertyType='Double'/>
            <t:FieldURIOrConstant>
              <t:Constant Value='2'/>
            </t:FieldURIOrConstant>
          </t:IsEqualTo>
          <t:IsEqualTo>
            <t:ExtendedFieldURI DistinguishedPropertySetId='PublicStrings' PropertyName='crmLinkState' PropertyType='Double'/>
            <t:FieldURIOrConstant>
              <t:Constant Value='0'/>
            </t:FieldURIOrConstant>
          </t:IsEqualTo>
        </t:Or>
      </m:Restriction>
      <m:SortOrder>
        <t:FieldOrder Order='Descending'>
          <t:FieldURI FieldURI='item:LastModifiedTime' />
        </t:FieldOrder>
      </m:SortOrder>
      <m:ParentFolderIds>
        <t:FolderId Id=").Append("'");
            
            if (selectedFolder == "0" || selectedFolder == "1" || selectedFolder == "9")
            {
                string folderId = EWSHelpers.GetFolderIdFromInt(selectedFolder, _exchangeproxy);
                sbBody.Append(folderId).Append("'").Append(" />");
            }
            else
            {
                sbBody.Append(selectedFolder).Append("'").Append(" />");
            }
            
            sbBody.Append(@"</m:ParentFolderIds>
    </m:FindItem>
  </soap:Body>
</soap:Envelope>");

            return sbBody.ToString();
        }

        private string GetFolder(string folderId)
        {
            if (folderId == "0")
            {
                Folder calendar = Folder.Bind(_exchangeproxy, WellKnownFolderName.Calendar);
                return calendar.Id.ToString();
            }

            else if (folderId == "1")
            {
                Folder contacts = Folder.Bind(_exchangeproxy, WellKnownFolderName.Contacts);
                return contacts.Id.ToString();
            }

            else
            {
                Folder tasks = Folder.Bind(_exchangeproxy, WellKnownFolderName.Tasks);
                return tasks.Id.ToString();
            }
        }

        private void BuildFindItemEmail()
        {
            //To-Do: Get output of EnvelopeXml from a shared method.
            string EnvelopeXml = @"<?xml version='1.0' encoding='utf-8'?><soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema'>";
            string BodyXml = GetFindItemBody();
            SendToPostForm(BodyXml, EnvelopeXml);
        }

        private string GetFindItemBody()
        {
            StringBuilder sbBodyXml = new StringBuilder();
            sbBodyXml.Append(@"<soap:Body>
        <FindItem Traversal='Shallow' xmlns='http://schemas.microsoft.com/exchange/services/2006/messages'>
            <ItemShape>
                <BaseShape xmlns = 'http://schemas.microsoft.com/exchange/services/2006/types' >IdOnly</BaseShape>
                <AdditionalProperties xmlns = 'http://schemas.microsoft.com/exchange/services/2006/types'>
                    <FieldURI FieldURI='item:LastModifiedTime'/>
                    <FieldURI FieldURI='message:InternetMessageId'/>
                    <FieldURI FieldURI='item:ParentFolderId'/>
                    <ExtendedFieldURI DistinguishedPropertySetId='PublicStrings' PropertyName='crmLinkState' PropertyType='Double' />
                    <ExtendedFieldURI DistinguishedPropertySetId='PublicStrings' PropertyName='crmid' PropertyType='String' />
                    <ExtendedFieldURI DistinguishedPropertySetId='PublicStrings' PropertyName='crmRegardingId' PropertyType='String' />
                </AdditionalProperties>
            </ItemShape>
            <IndexedPageItemView MaxEntriesReturned='");
            sbBodyXml.Append(numMaxEntriesReturned.Value).Append(@"'");
            sbBodyXml.Append(@" Offset='").Append(numOffset.Value).Append(@"'");
            sbBodyXml.Append(@" BasePoint='Beginning'/>");

            if (rdInbox.Checked)
            {
                sbBodyXml.Append(@"<Restriction>
                <Contains ContainmentMode='Prefixed' ContainmentComparison='IgnoreCase' xmlns='http://schemas.microsoft.com/exchange/services/2006/types'>
                    <FieldURI FieldURI='item:ItemClass'/>
                    <Constant Value='IPM.NOTE'/>
                </Contains>
            </Restriction>");

            sbBodyXml.Append(GetSortOrderXml());

                sbBodyXml.Append(@"<ParentFolderIds>
                <DistinguishedFolderId Id='inbox' xmlns='http://schemas.microsoft.com/exchange/services/2006/types'>
                    <Mailbox>
                        <EmailAddress>");
           
                sbBodyXml.Append(CrmOrgMailboxCache.TargetMailboxEmailAddress);
                sbBodyXml.Append(@"</EmailAddress></Mailbox></DistinguishedFolderId></ParentFolderIds></FindItem></soap:Body></soap:Envelope>");
                return sbBodyXml.ToString();
            }

            string ParentFolderId = GetCrmPendingLinkingFolderItemId();
            sbBodyXml.Append(GetSortOrderXml());
            sbBodyXml.Append(@"<ParentFolderIds><FolderId Id=").Append(@"'").Append(ParentFolderId).Append(@"'").Append(@" xmlns='http://schemas.microsoft.com/exchange/services/2006/types' />
            </ParentFolderIds>
        </FindItem>
    </soap:Body>
</soap:Envelope>");
       
            return sbBodyXml.ToString();

        }

        private string GetSortOrderXml()
        {
            string sortorderxml = @"<SortOrder>
                <FieldOrder Order = 'Descending' xmlns = 'http://schemas.microsoft.com/exchange/services/2006/types'>
                    <FieldURI FieldURI = 'item:LastModifiedTime'/>
                </FieldOrder>
                <FieldOrder Order = 'Descending' xmlns = 'http://schemas.microsoft.com/exchange/services/2006/types'>
                    <FieldURI FieldURI = 'message:InternetMessageId'/>
                </FieldOrder>
            </SortOrder>";

            return sortorderxml;
        }

        private string GetCrmPendingLinkingFolderItemId()
        {
            FolderView view = new FolderView(1);
            view.PropertySet = new PropertySet(BasePropertySet.IdOnly);
            SearchFilter searchFilter = new SearchFilter.IsEqualTo(FolderSchema.DisplayName, "CrmEmailMessagesPendingLinking");
            FindFoldersResults findFolderResult = _exchangeproxy.FindFolders(WellKnownFolderName.SearchFolders, view);

            if (findFolderResult.TotalCount <= 0)
            {
                throw new Exception("Did not find the CrmEmailMessagesPendingLinking search folder.");
            }

            return findFolderResult.Folders[0].Id.ToString();

        }

        private void chkUseSyncState_CheckedChanged(object sender, EventArgs e)
        {
            if (chkUseSyncState.Checked)
            {
                txtSyncState.Enabled = true;
            }
            else
            {
                txtSyncState.Enabled = false;
            }
        }

        private void btnLoadFolders_Click(object sender, EventArgs e)
        {
            string exchangeSyncStateXml = ExchangeSyncStateXml.GetCurrentExchangeSyncStateXml();
            ResetFolders(listvwFolders);
            PopulateListView(ExchangeSyncStateXml.GetExchangeFolderSyncStateCollectionFromXpath("ExchangeSyncState/LastFolderItemsSyncStates", exchangeSyncStateXml), listvwFolders);
        }

        private void ResetFolders(ListView folders)
        {
            if (folders.Items.Count > 0)
            {
                int idx = folders.Items.Count - 1;
                while (idx > -1)
                {
                    folders.Items.RemoveAt(idx);
                    idx = idx - 1;
                }
            }
        }

        private void PopulateListView(List<ExchangeFolderSyncState> FolderSyncStates, ListView listview)
        {
            foreach (ExchangeFolderSyncState folder in FolderSyncStates)
            {
                ListViewItem item = new ListViewItem();
                item.Text = folder.FolderName;
                item.ImageIndex = 0;
                item.Tag = folder;
                listview.Items.Add(item);
            }

        }

        private void btnGetSyncFolderHierarchyFolders_Click(object sender, EventArgs e)
        {
            ResetFolders(listvwSyncFolderHierarchyFolders);
            string exchangeSyncStateXml = ExchangeSyncStateXml.GetCurrentExchangeSyncStateXml();
            List<ExchangeFolderSyncState> syncFolderHierarchyFolders = ExchangeSyncStateXml.GetExchangeFolderSyncStateCollectionFromXpath("ExchangeSyncState/LastFolderHierarchySyncStates", exchangeSyncStateXml);
            PopulateListView(syncFolderHierarchyFolders, listvwSyncFolderHierarchyFolders);
        }

        private void listvwSyncFolderHierarchyFolders_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listvwSyncFolderHierarchyFolders.SelectedItems.Count == 0)
            {
                return;
            }

            var selectedItem = listvwSyncFolderHierarchyFolders.SelectedItems[0];
            if (selectedItem.Tag != null)
            {
                txtSyncState.Text = ((ExchangeFolderSyncState)selectedItem.Tag).SyncState;
            }
        }
    }
}
